<?php
namespace Lge;

if (!defined('LGE')) {
	exit('Include Permission Denied!');
}

/**
 * 基于禅道的KPI绩效考评统计.
 */
class Controller_ZentaoKpiStat extends Controller_Base
{
    public function index()
    {
        error_reporting(false);
        $option    = Lib_ConsoleOption::instance();
        $startDate = $option->getOption('start');
        $endDate   = $option->getOption('end');
        if (empty($startDate) || empty($endDate)) {
            Lib_Console::perrorln("start and end date should be given!");
            return;
        }
        $startTime   = date('Y-m-d 00:00:00', strtotime($startDate));
        $endTime     = date('Y-m-d 23:59:59', strtotime($endDate));
        $taskStat    = $this->_getTaskStat($startTime, $endTime);
        $bugStat     = $this->_getBugStat($startTime, $endTime);
        $qaStat      = $this->_getQaStat($startTime, $endTime);
        $totalHours  = 0;
        $totalNumber = 0;
        foreach ($taskStat as $name => $v) {
            $totalHours  += $v['hours'];
            $totalNumber += 1;
        }
        $averageHours = floor($totalHours/$totalNumber);
        echo "统计时间：{$startDate} - {$endDate}\n\n";
        echo "姓名,任务数/用例数,延迟数,工作量,团队平均工作量,单项任务平均工作量,开发环境BUG数,BUG延期3天,BUG延期5天\n";
        foreach ($taskStat as $name => $v) {
            $task               = $v;
            $taskCount          = count($task['ids']);
            $taskDelayCount     = count($task['delays']);
            $taskAverageHours   = floor($task['hours']/$taskCount);
            $bug                = $bugStat[$name];
            $bugDevCount        = count($bug['dev_ids']);
            $bugDelay3DaysCount = count($bug['delays']['3daysup']);
            $bugDelay5DaysCount = count($bug['delays']['5daysup']);
            $taskInfo           = "{$name},{$taskCount},{$taskDelayCount},{$task['hours']},{$averageHours},{$taskAverageHours}";
            $bugInfo            = "{$bugDevCount},{$bugDelay3DaysCount},{$bugDelay5DaysCount}";
            echo "{$taskInfo},{$bugInfo}\n";
        }
        foreach ($qaStat as $name => $v) {
            $caseCount   = count($v['case_ids']);
            $devBugCount = count($v['dev_ids']);
            echo "{$name},{$caseCount},0,0,0,{$devBugCount},0,0\n";
        }
        echo "\n";
    }

    /**
     * 获取任务统计结果
     *
     * @return array
     */
    private function _getTaskStat($startTime, $endTime)
    {
        $stat = array();
        $sql  = <<<MM
select zt_user.realname,zt_user.account,zt_task.* from zt_task
left join zt_user on(zt_user.account=zt_task.finishedBy)
where zt_user.role='dev' and openedDate between '{$startTime}' and '{$endTime}'
MM;
        $list = Instance::database('zentao')->getAll($sql);
        foreach ($list as $v) {
            if (!isset($stat[$v['realname']])) {
                $stat[$v['realname']] = array(
                    'ids'    => array(),
                    'delays' => array(),
                    'hours'  => 0,
                );
            }
            $s           = $stat[$v['realname']];
            $s['ids'][]  = $v['id'];
            $s['hours'] += empty($v['consumed']) ? $v['estimate'] : $v['consumed'];
            if (!empty($v['deadline']) && $v['deadline'] != '0000-00-00') {
                if (strtotime($v['finishedDate']) > strtotime("{$v['deadline']} 23:59:59")) {
                    $s['delays'][] = $v['id'];
                }
            }

            $stat[$v['realname']] = $s;
        }
        return $stat;
    }

    /**
     * 获取BUG统计结果
     *
     * @return array
     */
    private function _getBugStat($startTime, $endTime)
    {
        $stat = array();
        $sql1 = <<<MM
select zt_user.realname,zt_user.account,zt_bug.* from zt_bug 
left join zt_user on(zt_user.account=zt_bug.resolvedBy)
where zt_user.role='dev' and zt_bug.severity <=3 and assignedDate between '{$startTime}' and '{$endTime}'
MM;
        $list = Instance::database('zentao')->getAll($sql1);
        foreach ($list as $v) {
            if (!isset($stat[$v['realname']])) {
                $stat[$v['realname']] = array(
                    'dev_ids'     => array(),
                    'prod_ids'    => array(),
                    'delays'      => array(
                        '3daysup' => array(), // BUG处理延期超过3天的ID列表
                        '5daysup' => array(),
                    ),
                );
            }
            // 不算“外部原因”的BUG
            if ($v['resolution'] == 'external') {
                continue;
            }
            $s = $stat[$v['realname']];
            if ($v['resolvedBuild'] == 'trunk') {
                $s['dev_ids'][]  = $v['id'];
            } else {
                $s['prod_ids'][] = $v['id'];
            }
            $assignedDate = $this->_getBugFirstAssignTimeByAccount($v['id'], $v['account']);
            if (empty($assignedDate)) {
                $assignedDate = strtotime($v['assignedDate']);
            }
            if (!$this->_canBugBePostponed($v['id'])) {
                $delayDays = (strtotime($v['resolvedDate']) - $assignedDate)/86400;
                if ($delayDays > 3) {
                    $s['delays']['3daysup'][] = $v['id'];
                }
                if ($delayDays > 5) {
                    $s['delays']['5daysup'][] = $v['id'];
                }
            }
            $stat[$v['realname']] = $s;
        }
        return $stat;
    }

    /**
     * 判断BUG是否允许延期
     *
     * @param $id
     *
     * @return bool
     */
    private function _canBugBePostponed($bugid)
    {
        $sql = <<<MM
SELECT * FROM zt_action 
left join zt_bug on(zt_bug.resolvedBy!=zt_action.actor and zt_bug.id=zt_action.objectID)
where zt_bug.id is not null and objectType='bug' and objectID={$bugid} and action='resolved' and extra='postponed'
MM;
        $r = Instance::database('zentao')->getCount($sql);
        return !empty($r);
    }

    /**
     * 获取测试统计结果
     *
     * @return array
     */
    private function _getQaStat($startTime, $endTime)
    {
        $stat = array();
        // 测试建立的用例数
        $sql1 = <<<MM
select zt_case.id,zt_user.realname from zt_case
left join zt_user on(zt_user.account=zt_case.openedBy)
where zt_user.role in('qa','qd') and zt_case.openedDate between '{$startTime}' and '{$endTime}'
MM;
        $list = Instance::database('zentao')->getAll($sql1);
        foreach ($list as $v) {
            if (!isset($stat[$v['realname']])) {
                $stat[$v['realname']] = array(
                    'dev_ids'   => array(),
                    'case_ids'  => array(),
                );
            }
            $stat[$v['realname']]['case_ids'][] = $v['id'];
        }


        // 测试发现的BUG
        $sql1 = <<<MM
select zt_bug.id,zt_user.realname from zt_bug 
left join zt_user on(zt_user.account=zt_bug.openedBy)
where zt_user.role in('qa','qd') and zt_bug.severity <=3 and zt_bug.openedBuild='trunk' and zt_bug.openedDate between '{$startTime}' and '{$endTime}'
MM;
        $list = Instance::database('zentao')->getAll($sql1);
        foreach ($list as $v) {
            if (!isset($stat[$v['realname']])) {
                $stat[$v['realname']] = array(
                    'dev_ids'  => array(),
                    'case_ids' => array(),
                );
            }
            $stat[$v['realname']]['dev_ids'][]  = $v['id'];
        }
        // 非测试发现的BUG
//        $sql2 = <<<MM
//select zt_bug.id,zt_user.realname from zt_bug
//left join zt_user on(zt_user.account=zt_bug.openedBy)
//where zt_user.role not in('qa','qd') and zt_bug.severity <=3 and zt_bug.openedBuild != 'trunk' and zt_bug.openedDate between '{$startTime}' and '{$endTime}'
//MM;
//        $list = Instance::database('zentao')->getAll($sql2);
//        foreach ($list as $item) {
//            foreach ($stat as $k => $v) {
//                $stat[$k]['prod_ids'][] = $item['id'];
//            }
//        }
        return $stat;
    }

    /**
     * 获得用户首次被分配BUG修复的时间，如果没有分配表示是BUG创建时已经分配好，否则按照分配时间来计算BUG延期.
     *
     * @param $bugid
     *
     * @return integer
     */
    private function _getBugFirstAssignTimeByAccount($bugid, $account) {
        $sql = <<<MM
SELECT * FROM zt_action where objectType='bug' and objectID={$bugid} and action='assigned' and `extra`='{$account}' order by id asc
MM;
        $one = Instance::database('zentao')->getOne($sql);
        if (!empty($one) && !empty($one['date'])) {
            return strtotime($one['date']);
        }
        return 0;
    }
}
